// PanelListNotify.cpp

#include "StdAfx.h"
#include "Panel.h"

#include "Common/MS/PropVariant.h"
#include "Common/String/DataConversions.h"

#include "Common/Props/PropIDUtils.h"
#include "Common/7Zip/PropID.h"


#include "Common/String/FormatUtils.h"

#include "FileManager/Windows.h"

using namespace Common;


LRESULT CPanel::SetItemText(LVITEMW &item)
{
	if (_dontShowMode)
	{
		return 0;
	}

	UINT32 realIndex = GetRealIndex(item);

	if ((item.mask & LVIF_TEXT) == 0)
	{
		return 0;
	}

	if (realIndex == FileManager::FileSystem::kParentIndex)
	{
		return 0;
	}
	CString s;
	UINT32 subItemIndex = item.iSubItem;
	PROPID propID = m_directory.GetVisibleProperties()[subItemIndex].ID;

	CComPropVariant prop;

	HRESULT res = m_directory.GetIFolder()->GetProperty(realIndex, propID, &prop);
	if (res != S_OK)
	{
		s = CString(_T("Error: ")) + FileManager::CWindows::HResultToMessage(res);
	}
	else if ((prop.vt == VT_UI8 || prop.vt == VT_UI4) && (
				 propID == kpidSize ||
				 propID == kpidPackSize ||
				 propID == kpidNumSubDirs ||
				 propID == kpidNumSubFiles ||
				 propID == kpidPosition ||
				 propID == kpidNumBlocks ||
				 propID == kpidClusterSize ||
				 propID == kpidTotalSize ||
				 propID == kpidFreeSpace
			 ))
	{
		s = String::ConvertSizeToString(String::ConvertPropVariantToUInt64(prop));
	}
	else
	{
		s = Props::ConvertPropertyToString(prop, propID, false);
		s.Replace(wchar_t(0xA), _T(' '));
		s.Replace(wchar_t(0xD), _T(' '));
	}
	int size = item.cchTextMax;
	if (size > 0)
	{
		if (s.GetLength() + 1 > size)
		{
			s = s.Left(size - 1);
		}
		wcscpy(item.pszText, s);
	}
	return 0;
}

void CPanel::OnItemChanged(NMLISTVIEW* item)
{
	int index = (int)item->lParam;
	if (index == FileManager::FileSystem::kParentIndex)
	{
		return;
	}
	bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0;
	bool newSelected = (item->uNewState & LVIS_SELECTED) != 0;
	// Don't change this code. It works only with such check
	if (oldSelected != newSelected)
	{
		_selectedStatusVector[index] = newSelected;
	}
}

void CPanel::OnNotifyActivateItems()
{
	// bool leftCtrl = (::GetKeyState(VK_LCONTROL) & 0x8000) != 0;
	// bool rightCtrl = (::GetKeyState(VK_RCONTROL) & 0x8000) != 0;
	bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
	bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
	bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
	if (!shift && alt && !ctrl)
	{
		Properties();
	}
	else
	{
		OpenSelectedItems(!shift || alt || ctrl);
	}
}

bool CPanel::OnNotifyList(LPNMHDR header, LRESULT &result,  BOOL &bHandled)
{
	switch(header->code)
	{
		case LVN_ITEMCHANGED:
		{
			if (_enableItemChangeNotify)
			{
				if (!_mySelectMode)
				{
					OnItemChanged((LPNMLISTVIEW)header);
				}
				RefreshStatusBar();
			}
			return false;
		}


		case LVN_GETDISPINFOW:
		{
			LV_DISPINFOW* dispInfo = (LV_DISPINFOW*)header;

			//is the sub-item information being requested?

			if ((dispInfo->item.mask & LVIF_TEXT) != 0 ||
					(dispInfo->item.mask & LVIF_IMAGE) != 0)
			{
				SetItemText(dispInfo->item);
			}
			return false;
		}
		case LVN_KEYDOWN:
		{
			bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header), result);
			RefreshStatusBar();
			return boolResult;
		}

		case LVN_COLUMNCLICK:
			OnColumnClick(LPNMLISTVIEW(header));
			return false;

		case LVN_ITEMACTIVATE:
			OnNotifyActivateItems();
			return false;
		case NM_DBLCLK:
		case NM_RETURN:
			OnNotifyActivateItems();
			//bHandled = FALSE;
			return true;
		case NM_RCLICK:
			RefreshStatusBar();
			break;

		/*
		  return OnRightClick((LPNMITEMACTIVATE)header, result);
		*/
		/*
		case NM_CLICK:
		SendRefreshStatusBarMessage();
		return 0;

		  // TODO : Handler default action...
		  return 0;
		  case LVN_ITEMCHANGED:
		  {
		  NMLISTVIEW *pNMLV = (NMLISTVIEW *) lpnmh;
		  SelChange(pNMLV);
		  return TRUE;
		  }
		  case NM_SETFOCUS:
		  return onSetFocus(NULL);
		  case NM_KILLFOCUS:
		  return onKillFocus(NULL);
		*/
		case NM_CLICK:
		{
			// we need SetFocusToList, if we drag-select items from other panel.
			SetFocusToList();
			RefreshStatusBar();
			if (_mySelectMode)
			{
				OnLeftClick((MY_NMLISTVIEW_NMITEMACTIVATE*)header);
			}
			else
			{
				bHandled = FALSE;
			}
			return false;
		}
		case LVN_BEGINLABELEDITW:
			result = OnBeginLabelEdit((LV_DISPINFOW*)header);
			bHandled = FALSE;
			return true;
		case LVN_ENDLABELEDITW:
			result = OnEndLabelEdit((LV_DISPINFOW*)header);
			return true;

		case NM_CUSTOMDRAW:
		{
			if (_mySelectMode)
			{
				return OnCustomDraw((LPNMLVCUSTOMDRAW)header, result);
			}
			else
			{
				bHandled = FALSE;
			}
			break;
		}
		case LVN_BEGINDRAG:
		{
			OnDrag((LPNMLISTVIEW)header);
			RefreshStatusBar();
			break;
		}
			// case LVN_BEGINRDRAG:
	}
	bHandled = FALSE;
	return false;
}

bool CPanel::OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result)
{
	switch(lplvcd->nmcd.dwDrawStage)
	{
		case CDDS_PREPAINT :
			result = CDRF_NOTIFYITEMDRAW;
			return true;

		case CDDS_ITEMPREPAINT:
			int realIndex = (int)lplvcd->nmcd.lItemlParam;
			bool selected = false;
			if (realIndex != FileManager::FileSystem::kParentIndex)
			{
				selected = _selectedStatusVector[realIndex];
			}
			if (selected)
			{
				lplvcd->clrTextBk = RGB(255, 192, 192);
			}
			else
			{
				lplvcd->clrTextBk = _listView.GetBkColor();
			}
			result = CDRF_NOTIFYITEMDRAW;
			return true;

			/* At this point, you can change the background colors for the item
			    and any subitems and return CDRF_NEWFONT. If the list-view control
			    is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW
			    to customize the item's subitems individually */
	}
	return false;
}

LRESULT CPanel::OnRefreshStatusBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & /*bHandled*/)
{
	OnRefreshStatusBar();
	return 0;
}

void CPanel::OnRefreshStatusBar()
{
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);

	_statusBar.SetText(0, String::PatternFormat(IDS_N_SELECTED_ITEMS, 0x02000301, String::NumberToString(indices.size())));

	CString selectSizeString;

	if (indices.size() > 0)
	{
		UINT64 totalSize = 0;
		for (size_t i = 0; i < indices.size(); i++)
		{
			totalSize += m_directory.GetItemSize(indices[i]);
		}
		selectSizeString = String::ConvertSizeToString(totalSize);
	}
	_statusBar.SetText(1, selectSizeString);

	int focusedItem = _listView.GetNextItem(-1, LVNI_FOCUSED);
	CString sizeString;
	CString dateString;
	if (focusedItem >= 0 && _listView.GetSelectedCount() > 0)
	{
		int realIndex = GetRealItemIndex(focusedItem);
		if (realIndex != FileManager::FileSystem::kParentIndex)
		{
			sizeString = String::ConvertSizeToString(m_directory.GetItemSize(realIndex));
			CComPropVariant prop;
			if (m_directory.GetIFolder()->GetProperty(realIndex, kpidMTime, &prop) == S_OK)
			{
				dateString = Props::ConvertPropertyToString(prop, kpidMTime, false);
			}
		}
	}
	_statusBar.SetText(2, sizeString);
	_statusBar.SetText(3, dateString);
}
